/*
 * Copyright (C) Hisilicon Technologies Co., Ltd. 2018-2019. All rights reserved.
 * Description:
 * Author:
 * Create: 2018-05-19
 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#ifdef ON_BOARD
#include <string.h>
#include <unistd.h>
#include <libgen.h>
#include "math.h"
#include "mpi_ive.h"
#include "mpi_sys.h"
#include "hi_comm_ive.h"
#include "sample_log.h"
#include "sample_memory_ops.h"
#include "sample_save_blob.h"
#include "sample_resize_roi.h"
#include "sample_data_utils.h"

static const HI_U32 WAIT_TIME = 100;
static const HI_U32 BLUE_IDX = 0;
static const HI_U32 GREEN_IDX = 1;
static const HI_U32 RED_IDX = 2;

HI_S32 ive_copy_singal_small(IVE_DATA_S *pstSrc, IVE_DATA_S *pstDst)
{
    HI_U8 *pu8Src = (HI_U8 *)((uintptr_t)pstSrc->u64VirAddr);
    HI_U8 *pu8Dst = (HI_U8 *)((uintptr_t)pstDst->u64VirAddr);
    for (HI_U32 i = 0; i < pstSrc->u32Height; i++) {
        for (HI_U32 j = 0; j < pstSrc->u32Width; j++) {
            pu8Dst[i * pstDst->u32Stride + j] = pu8Src[i * pstSrc->u32Stride + j];
        }
    }
    return HI_SUCCESS;
}

HI_S32 iveDmaCopy(IVE_HANDLE *pIveHandle, IVE_DATA_S *pstSrc,
                  IVE_DST_DATA_S *pstDst, IVE_DMA_CTRL_S *pstDmaCtrl, HI_BOOL bInstant)
{
    HI_S32 s32Ret = HI_FAILURE;
    HI_BOOL bFinish = HI_FALSE;
    struct timespec request_time;

    request_time.tv_sec = 0;
    request_time.tv_nsec = WAIT_TIME * MICROSECOND_PER_SECOND;

    if ((pstSrc->u32Height < 32) || (pstSrc->u32Width < 32)) {
        return ive_copy_singal_small(pstSrc, pstDst);
    } else {
        s32Ret = HI_MPI_IVE_DMA(pIveHandle, pstSrc, pstDst, pstDmaCtrl, bInstant);
        if ((bInstant == HI_TRUE) && (s32Ret == HI_SUCCESS)) {
            s32Ret = HI_MPI_IVE_Query(*pIveHandle, &bFinish, HI_TRUE);
            while (s32Ret == HI_ERR_IVE_QUERY_TIMEOUT) {
                nanosleep(&request_time, HI_NULL);
                SAMPLE_LOG_INFO("HI_MPI_IVE_Query timeout, wait 100us");
                s32Ret = HI_MPI_IVE_Query(*pIveHandle, &bFinish, HI_TRUE);
            }
        }
        return s32Ret;
    }
}

static HI_U32 iveCalcStride(IVE_IMAGE_TYPE_E enType, HI_U32 u32Width, HI_U8 u8Align)
{
    HI_U32 u32Size = 0;

    switch (enType) {
        case IVE_IMAGE_TYPE_U8C1:
        case IVE_IMAGE_TYPE_S8C1:
        case IVE_IMAGE_TYPE_S8C2_PACKAGE:
        case IVE_IMAGE_TYPE_S8C2_PLANAR:
        case IVE_IMAGE_TYPE_U8C3_PACKAGE:
        case IVE_IMAGE_TYPE_U8C3_PLANAR: {
            u32Size = sizeof(HI_U8);
        }
        break;
        case IVE_IMAGE_TYPE_S16C1:
        case IVE_IMAGE_TYPE_U16C1: {
            u32Size = sizeof(HI_U16);
        }
        break;
        case IVE_IMAGE_TYPE_S32C1:
        case IVE_IMAGE_TYPE_U32C1: {
            u32Size = sizeof(HI_U32);
        }
        break;
        case IVE_IMAGE_TYPE_S64C1:
        case IVE_IMAGE_TYPE_U64C1: {
            u32Size = sizeof(HI_U64);
        }
        break;
        default:
            break;
    }

    if (u8Align == ALIGN_16) {
        return getAlignSize(ALIGN_16, u32Width * u32Size);
    } else {
        return getAlignSize(ALIGN_32, u32Width * u32Size);
    }
}

static HI_VOID setIveImage(IVE_IMAGE_S *pstImg, HI_U8 u8C1, HI_U8 u8C2, HI_U8 u8C3)
{
    HI_U32 u32OneCSize = pstImg->au32Stride[0] * pstImg->u32Height;
    // 0 1 2 is image color channel index
    memset ((HI_U8 *)((uintptr_t) pstImg->au64VirAddr[0]), (HI_S32)u8C1, u32OneCSize);
    memset ((HI_U8 *)((uintptr_t) pstImg->au64VirAddr[1]), (HI_S32)u8C2, u32OneCSize);
    memset ((HI_U8 *)((uintptr_t) pstImg->au64VirAddr[2]), (HI_S32)u8C3, u32OneCSize);
}

static HI_S32 CreateU8C1OrS8C1Image(IVE_IMAGE_S *pstImg)
{
    HI_U32 u32Size = pstImg->au32Stride[0] * pstImg->u32Height;
    HI_S32 s32Ret = HI_MPI_SYS_MmzAlloc(&pstImg->au64PhyAddr[0], (HI_VOID **)&pstImg->au64VirAddr[0],
        HI_NULL, HI_NULL, u32Size);
    if (s32Ret != HI_SUCCESS) {
        SAMPLE_LOG_INFO("Mmz Alloc fail,Error(%#x)", s32Ret);
        return s32Ret;
    }
    return s32Ret;
}

static HI_S32 CreateYUV420SPImage(IVE_IMAGE_S *pstImg)
{
    HI_U32 u32Size = pstImg->au32Stride[0] * pstImg->u32Height * 3 / 2; // YUV420 format data size
    HI_S32 s32Ret = HI_MPI_SYS_MmzAlloc(&pstImg->au64PhyAddr[0],
        (HI_VOID **)&pstImg->au64VirAddr[0], HI_NULL, HI_NULL, u32Size);
    if (s32Ret != HI_SUCCESS) {
        SAMPLE_LOG_INFO("Mmz Alloc fail,Error(%#x)", s32Ret);
        return s32Ret;
    }
    pstImg->au32Stride[1] = pstImg->au32Stride[0];
    pstImg->au64PhyAddr[1] = pstImg->au64PhyAddr[0] + pstImg->au32Stride[0] * (HI_U64)pstImg->u32Height;
    pstImg->au64VirAddr[1] = pstImg->au64VirAddr[0] + pstImg->au32Stride[0] * (HI_U64)pstImg->u32Height;
    return s32Ret;
}

static HI_S32 CreateYUV422SPImage(IVE_IMAGE_S *pstImg)
{
    HI_U32 u32Size = pstImg->au32Stride[0] * pstImg->u32Height * 2; // YUV422 format data size
    HI_S32 s32Ret = HI_MPI_SYS_MmzAlloc(&pstImg->au64PhyAddr[0],
        (HI_VOID **)&pstImg->au64VirAddr[0], HI_NULL, HI_NULL, u32Size);
    if (s32Ret != HI_SUCCESS) {
        SAMPLE_LOG_INFO("Mmz Alloc fail,Error(%#x)", s32Ret);
        return s32Ret;
    }
    pstImg->au32Stride[1] = pstImg->au32Stride[0];
    pstImg->au64PhyAddr[1] = pstImg->au64PhyAddr[0] + pstImg->au32Stride[0] * (HI_U64)pstImg->u32Height;
    pstImg->au64VirAddr[1] = pstImg->au64VirAddr[0] + pstImg->au32Stride[0] * (HI_U64)pstImg->u32Height;
    return s32Ret;
}

static HI_S32 CreateS16C1OrU16C1Image(IVE_IMAGE_S *pstImg)
{
    HI_U32 u32Size = pstImg->au32Stride[0] * pstImg->u32Height * sizeof(HI_U16);
    HI_S32 s32Ret = HI_MPI_SYS_MmzAlloc(&pstImg->au64PhyAddr[0],
        (HI_VOID **)&pstImg->au64VirAddr[0], HI_NULL, HI_NULL, u32Size);
    if (s32Ret != HI_SUCCESS) {
        SAMPLE_LOG_INFO("Mmz Alloc fail,Error(%#x)", s32Ret);
        return s32Ret;
    }
    return s32Ret;
}

static HI_S32 CreateU8C3PackageImage(IVE_IMAGE_S *pstImg)
{
    HI_U32 u32Size = pstImg->au32Stride[0] * pstImg->u32Height * 3; // package format data size
    HI_S32 s32Ret = HI_MPI_SYS_MmzAlloc(&pstImg->au64PhyAddr[0],
        (HI_VOID **)&pstImg->au64VirAddr[0], HI_NULL, HI_NULL, u32Size);
    if (s32Ret != HI_SUCCESS) {
        SAMPLE_LOG_INFO("Mmz Alloc fail,Error(%#x)", s32Ret);
        return s32Ret;
    }
    pstImg->au64VirAddr[GREEN_IDX] = pstImg->au64VirAddr[BLUE_IDX] + 1;
    pstImg->au64VirAddr[RED_IDX] = pstImg->au64VirAddr[GREEN_IDX] + 1;
    pstImg->au64PhyAddr[GREEN_IDX] = pstImg->au64PhyAddr[BLUE_IDX] + 1;
    pstImg->au64PhyAddr[RED_IDX] = pstImg->au64PhyAddr[GREEN_IDX] + 1;
    pstImg->au32Stride[GREEN_IDX] = pstImg->au32Stride[BLUE_IDX];
    pstImg->au32Stride[RED_IDX] = pstImg->au32Stride[BLUE_IDX];
    return s32Ret;
}

static HI_S32 CreateU8C3PlanarImage(IVE_IMAGE_S *pstImg)
{
    // every channel has the same stride
    HI_U32 u32OneCSize = pstImg->au32Stride[0] * pstImg->u32Height;
    HI_U32 u32Size = u32OneCSize * 3; // RGB_image have 3 channel
    HI_S32 s32Ret = HI_MPI_SYS_MmzAlloc(&pstImg->au64PhyAddr[0],
        (HI_VOID **)&pstImg->au64VirAddr[0], HI_NULL, HI_NULL, u32Size);
    if (s32Ret != HI_SUCCESS) {
        SAMPLE_LOG_INFO("Mmz Alloc fail,Error(%#x)", s32Ret);
        return s32Ret;
    }
    pstImg->au64VirAddr[GREEN_IDX] = pstImg->au64VirAddr[BLUE_IDX] + u32OneCSize;
    pstImg->au64VirAddr[RED_IDX] = pstImg->au64VirAddr[GREEN_IDX] + u32OneCSize;
    pstImg->au64PhyAddr[GREEN_IDX] = pstImg->au64PhyAddr[BLUE_IDX] + u32OneCSize;
    pstImg->au64PhyAddr[RED_IDX] = pstImg->au64PhyAddr[GREEN_IDX] + u32OneCSize;
    pstImg->au32Stride[GREEN_IDX] = pstImg->au32Stride[BLUE_IDX];
    pstImg->au32Stride[RED_IDX] = pstImg->au32Stride[BLUE_IDX];
    return s32Ret;
}

static HI_S32 CreateS32C1OrU32C1Image(IVE_IMAGE_S *pstImg)
{
    HI_U32 u32Size = pstImg->au32Stride[0] * pstImg->u32Height * sizeof(HI_U32);
    HI_S32 s32Ret = HI_MPI_SYS_MmzAlloc(&pstImg->au64PhyAddr[0],
        (HI_VOID **)&pstImg->au64VirAddr[0], HI_NULL, HI_NULL, u32Size);
    if (s32Ret != HI_SUCCESS) {
        SAMPLE_LOG_INFO("Mmz Alloc fail,Error(%#x)", s32Ret);
        return s32Ret;
    }
    return s32Ret;
}

static HI_S32 CreateS64C1OrU64C1Image(IVE_IMAGE_S *pstImg)
{
    HI_U32 u32Size = pstImg->au32Stride[0] * pstImg->u32Height * sizeof(HI_U64);
    HI_S32 s32Ret = HI_MPI_SYS_MmzAlloc(&pstImg->au64PhyAddr[0],
        (HI_VOID **)&pstImg->au64VirAddr[0], HI_NULL, HI_NULL, u32Size);
    if (s32Ret != HI_SUCCESS) {
        SAMPLE_LOG_INFO("Mmz Alloc fail,Error(%#x)", s32Ret);
        return s32Ret;
    }
    return s32Ret;
}

typedef HI_S32 (*CreateImageFun)(IVE_IMAGE_S*);

typedef struct {
    IVE_IMAGE_TYPE_E enType;
    CreateImageFun imageFun;
} CreateImageMap;

CreateImageMap imageMap[] = {
    { IVE_IMAGE_TYPE_U8C1, CreateU8C1OrS8C1Image },
    { IVE_IMAGE_TYPE_S8C1, CreateU8C1OrS8C1Image },
    { IVE_IMAGE_TYPE_YUV420SP, CreateYUV420SPImage },
    { IVE_IMAGE_TYPE_YUV422SP, CreateYUV422SPImage },
    { IVE_IMAGE_TYPE_S16C1, CreateS16C1OrU16C1Image },
    { IVE_IMAGE_TYPE_U16C1, CreateS16C1OrU16C1Image },
    { IVE_IMAGE_TYPE_U8C3_PACKAGE, CreateU8C3PackageImage },
    { IVE_IMAGE_TYPE_U8C3_PLANAR, CreateU8C3PlanarImage },
    { IVE_IMAGE_TYPE_S32C1, CreateS32C1OrU32C1Image },
    { IVE_IMAGE_TYPE_U32C1, CreateS32C1OrU32C1Image },
    { IVE_IMAGE_TYPE_S64C1, CreateS64C1OrU64C1Image },
    { IVE_IMAGE_TYPE_U64C1, CreateS64C1OrU64C1Image }
};

static HI_S32 createImageByIVE(IVE_IMAGE_S *pstImg, IVE_IMAGE_TYPE_E enType, HI_U32 u32Width, HI_U32 u32Height)
{
    HI_S32 s32Ret = HI_FAILURE;
    if (pstImg == NULL) {
        SAMPLE_LOG_INFO("pstImg is null");
        return HI_FAILURE;
    }

    pstImg->enType = enType;
    pstImg->u32Width = u32Width;
    pstImg->u32Height = u32Height;
    pstImg->au32Stride[0] = iveCalcStride(pstImg->enType, pstImg->u32Width, ALIGN_16);

    HI_U32 mapSize = sizeof(imageMap) / sizeof(CreateImageMap);
    CreateImageFun imageFunc = HI_NULL;
    for (HI_U32 i = 0; i < mapSize; ++i) {
        if (imageMap[i].enType == enType) {
            imageFunc = imageMap[i].imageFun;
            break;
        }
    }

    if (imageFunc != HI_NULL) {
        s32Ret = (*imageFunc)(pstImg);
        SAMPLE_CHK_RET(s32Ret != HI_SUCCESS, HI_FAILURE, "createImageByIVE failed");
    }

    return HI_SUCCESS;
}

static HI_VOID freeIveImage(IVE_IMAGE_S *pstImage)
{
    if ((pstImage->au64PhyAddr[0] != 0) && (pstImage->au64VirAddr[0] != 0)) {
        HI_MPI_SYS_MmzFree (pstImage->au64PhyAddr[0], (HI_VOID *)((uintptr_t)pstImage->au64VirAddr[0]));
        pstImage->au64PhyAddr[0] = 0;
        pstImage->au64VirAddr[0] = 0;
    }
    memset(pstImage, 0, sizeof(*pstImage));
}

static HI_S32 copyImageByIVE(IVE_IMAGE_S *pstSrcImage, IVE_IMAGE_S *pstDstImage, IVE_RECT_U16_S *pstDstRect)
{
    IVE_HANDLE hIveHandle;
    IVE_DATA_S stSrc;
    IVE_DATA_S stDst;
    IVE_DMA_CTRL_S stDmaCtrl = { IVE_DMA_MODE_DIRECT_COPY, 0, 0, 0, 0 };
    HI_U64 u64Offset = pstDstImage->au32Stride[0] * (HI_U64)pstDstRect->u16Y +
        (HI_U64)pstDstRect->u16X * sizeof(HI_U8);

    if (pstDstImage->enType != IVE_IMAGE_TYPE_U8C3_PLANAR) {
        SAMPLE_LOG_INFO("Invalid image type[%u]", pstDstImage->enType);
        return HI_FAILURE;
    }

    stSrc.u32Height = pstDstRect->u16Height;
    stSrc.u32Width = pstDstRect->u16Width;

    stDst.u32Height = pstDstRect->u16Height;
    stDst.u32Width = pstDstRect->u16Width;

    stSrc.u32Stride = pstSrcImage->au32Stride[BLUE_IDX];
    stSrc.u64PhyAddr = pstSrcImage->au64PhyAddr[BLUE_IDX];
    stSrc.u64VirAddr = pstSrcImage->au64VirAddr[BLUE_IDX];
    stDst.u32Stride = pstDstImage->au32Stride[BLUE_IDX];
    stDst.u64PhyAddr = pstDstImage->au64PhyAddr[BLUE_IDX] + u64Offset;
    stDst.u64VirAddr = pstDstImage->au64VirAddr[BLUE_IDX] + u64Offset;
    HI_S32 s32Ret = iveDmaCopy(&hIveHandle, &stSrc, &stDst, &stDmaCtrl, HI_FALSE);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "iveDmaCopy 0 fail!");

    stSrc.u32Stride = pstSrcImage->au32Stride[GREEN_IDX];
    stSrc.u64PhyAddr = pstSrcImage->au64PhyAddr[GREEN_IDX];
    stSrc.u64VirAddr = pstSrcImage->au64VirAddr[GREEN_IDX];
    stDst.u32Stride = pstDstImage->au32Stride[GREEN_IDX];
    stDst.u64PhyAddr = pstDstImage->au64PhyAddr[GREEN_IDX] + u64Offset;
    stDst.u64VirAddr = pstDstImage->au64VirAddr[GREEN_IDX] + u64Offset;
    s32Ret = iveDmaCopy(&hIveHandle, &stSrc, &stDst, &stDmaCtrl, HI_FALSE);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "iveDmaCopy 1 fail!");

    stSrc.u32Stride = pstSrcImage->au32Stride[RED_IDX];
    stSrc.u64PhyAddr = pstSrcImage->au64PhyAddr[RED_IDX];
    stSrc.u64VirAddr = pstSrcImage->au64VirAddr[RED_IDX];
    stDst.u32Stride = pstDstImage->au32Stride[RED_IDX];
    stDst.u64PhyAddr = pstDstImage->au64PhyAddr[RED_IDX] + u64Offset;
    stDst.u64VirAddr = pstDstImage->au64VirAddr[RED_IDX] + u64Offset;
    s32Ret = iveDmaCopy(&hIveHandle, &stSrc, &stDst, &stDmaCtrl, HI_TRUE);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "iveDmaCopy 2 fail!");

FAIL_0:
    return s32Ret;
}

static HI_S32 copyIveImage2Blob(const IVE_IMAGE_S *pstSrcImage, HI_RUNTIME_BLOB_S *pstDstBlobs, HI_U16 u16Index)
{
    HI_U32 u32DstWidth = pstDstBlobs->unShape.stWhc.u32Width;
    HI_U32 u32DstHeight = pstDstBlobs->unShape.stWhc.u32Height;
    HI_U32 u32DstStride = pstDstBlobs->u32Stride;
    HI_U8 *pu8Dst = (HI_U8 *)((uintptr_t)(pstDstBlobs->u64VirAddr + u16Index * u32DstHeight * u32DstStride *
                                          pstDstBlobs->unShape.stWhc.u32Chn));
    HI_U8 *pu8DstR = pu8Dst;
    HI_U8 *pu8DstG = pu8DstR + u32DstStride * u32DstHeight;
    HI_U8 *pu8DstB = pu8DstG + u32DstStride * u32DstHeight;

    if ((u32DstStride != pstSrcImage->au32Stride[0]) ||
        (u32DstHeight != pstSrcImage->u32Height) ||
        (u32DstWidth != pstSrcImage->u32Width)) {
        return HI_FAILURE;
    }

    HI_U32 u32OneCSize = u32DstStride * u32DstHeight;
    memcpy (pu8DstR, (HI_U8 *)(uintptr_t) pstSrcImage->au64VirAddr[BLUE_IDX], u32OneCSize);
    memcpy (pu8DstG, (HI_U8 *)(uintptr_t) pstSrcImage->au64VirAddr[GREEN_IDX], u32OneCSize);
    memcpy (pu8DstB, (HI_U8 *)(uintptr_t) pstSrcImage->au64VirAddr[RED_IDX], u32OneCSize);

    return HI_SUCCESS;
}

static HI_S32 copyBlob2IveImage(const HI_RUNTIME_BLOB_S *pstSrcBlob, HI_U16 u16Index, IVE_IMAGE_S *pstImage)
{
    HI_U32 u32SrcWidth = pstSrcBlob->unShape.stWhc.u32Width;
    HI_U32 u32SrcHeight = pstSrcBlob->unShape.stWhc.u32Height;
    HI_U32 u32SrcStride = pstSrcBlob->u32Stride;
    HI_U8 *pu8Src = (HI_U8 *)(uintptr_t)(pstSrcBlob->u64VirAddr + u16Index * u32SrcHeight * u32SrcStride *
                                         pstSrcBlob->unShape.stWhc.u32Chn);
    HI_U8 *pu8SrcR = pu8Src;
    HI_U8 *pu8SrcG = pu8SrcR + u32SrcStride * u32SrcHeight;
    HI_U8 *pu8SrcB = pu8SrcG + u32SrcStride * u32SrcHeight;

    if ((u32SrcStride != pstImage->au32Stride[0]) ||
        (u32SrcHeight != pstImage->u32Height) ||
        (u32SrcWidth != pstImage->u32Width)) {
        return HI_FAILURE;
    }

    HI_U32 u32OneCSize = u32SrcStride * u32SrcHeight;
    memcpy ((HI_U8 *)((uintptr_t) pstImage->au64VirAddr[BLUE_IDX]), pu8SrcR, u32OneCSize);
    memcpy ((HI_U8 *)((uintptr_t) pstImage->au64VirAddr[GREEN_IDX]), pu8SrcG, u32OneCSize);
    memcpy ((HI_U8 *)((uintptr_t) pstImage->au64VirAddr[RED_IDX]), pu8SrcB, u32OneCSize);

    return HI_SUCCESS;
}

static HI_S32 createRectImageByIVE(const IVE_IMAGE_S *pstImage, IVE_RECT_U16_S *pstRect, IVE_IMAGE_S *pstDstImage)
{
    IVE_HANDLE hIveHandle;
    IVE_DATA_S stSrc;
    IVE_DATA_S stDst;
    IVE_DMA_CTRL_S stDmaCtrl = { IVE_DMA_MODE_DIRECT_COPY, 0, 0, 0, 0 };
    HI_U64 u64Offset = pstImage->au32Stride[0] * (HI_U64)pstRect->u16Y + (HI_U64)pstRect->u16X * sizeof(HI_U8);

    if (pstImage->enType != IVE_IMAGE_TYPE_U8C3_PLANAR) {
        SAMPLE_LOG_INFO("Invalid image type[%u]", pstImage->enType);
        return HI_FAILURE;
    }

    HI_S32 s32Ret = createImageByIVE(pstDstImage, IVE_IMAGE_TYPE_U8C3_PLANAR, (HI_U32)pstRect->u16Width,
                                     (HI_U32)pstRect->u16Height);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "createImageByIVE fail!");

    stSrc.u32Height = pstRect->u16Height;
    stSrc.u32Width = pstRect->u16Width;

    stDst.u32Height = pstRect->u16Height;
    stDst.u32Width = pstRect->u16Width;

    stSrc.u32Stride = pstImage->au32Stride[BLUE_IDX];
    stSrc.u64PhyAddr = pstImage->au64PhyAddr[BLUE_IDX] + u64Offset;
    stSrc.u64VirAddr = pstImage->au64VirAddr[BLUE_IDX] + u64Offset;
    stDst.u32Stride = pstDstImage->au32Stride[BLUE_IDX];
    stDst.u64PhyAddr = pstDstImage->au64PhyAddr[BLUE_IDX];
    stDst.u64VirAddr = pstDstImage->au64VirAddr[BLUE_IDX];
    s32Ret = iveDmaCopy(&hIveHandle, &stSrc, &stDst, &stDmaCtrl, HI_FALSE);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "iveDmaCopy 0 fail!");

    stSrc.u32Stride = pstImage->au32Stride[GREEN_IDX];
    stSrc.u64PhyAddr = pstImage->au64PhyAddr[GREEN_IDX] + u64Offset;
    stSrc.u64VirAddr = pstImage->au64VirAddr[GREEN_IDX] + u64Offset;
    stDst.u32Stride = pstDstImage->au32Stride[GREEN_IDX];
    stDst.u64PhyAddr = pstDstImage->au64PhyAddr[GREEN_IDX];
    stDst.u64VirAddr = pstDstImage->au64VirAddr[GREEN_IDX];
    s32Ret = iveDmaCopy(&hIveHandle, &stSrc, &stDst, &stDmaCtrl, HI_FALSE);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "iveDmaCopy 1 fail!");

    stSrc.u32Stride = pstImage->au32Stride[RED_IDX];
    stSrc.u64PhyAddr = pstImage->au64PhyAddr[RED_IDX] + u64Offset;
    stSrc.u64VirAddr = pstImage->au64VirAddr[RED_IDX] + u64Offset;
    stDst.u32Stride = pstDstImage->au32Stride[RED_IDX];
    stDst.u64PhyAddr = pstDstImage->au64PhyAddr[RED_IDX];
    stDst.u64VirAddr = pstDstImage->au64VirAddr[RED_IDX];
    s32Ret = iveDmaCopy(&hIveHandle, &stSrc, &stDst, &stDmaCtrl, HI_TRUE);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "iveDmaCopy 2 fail!");
    return s32Ret;

FAIL_0:
    freeIveImage(pstDstImage);
    return s32Ret;
}

static HI_VOID cropImageByIVE(const IVE_IMAGE_S *pstImage, const BondingBox_s *pstTightBbox,
                              IVE_IMAGE_S *pstTarget, BondingBox_s *pstLocationBbox,
                              HI_DOUBLE *pEdgeX, HI_DOUBLE *pEdgeY)
{
    computeCropLocation(pstTightBbox, (HI_DOUBLE)pstImage->u32Width, (HI_DOUBLE)pstImage->u32Height,
                        pstLocationBbox);

    const HI_DOUBLE roi_left = min(pstLocationBbox->x1, (HI_DOUBLE)(pstImage->u32Width - 1));
    const HI_DOUBLE roi_bottom = min(pstLocationBbox->y1, (HI_DOUBLE)(pstImage->u32Height - 1));
    const HI_DOUBLE roi_width = min((HI_DOUBLE)(pstImage->u32Width),
        max(1.0, ceil(pstLocationBbox->x2 - pstLocationBbox->x1))); // width not less than 1.0
    const HI_DOUBLE roi_height = min((HI_DOUBLE)(pstImage->u32Height),
        max(1.0, ceil(pstLocationBbox->y2 - pstLocationBbox->y1))); // height not less than 1.0

    IVE_IMAGE_S stCroppedImage = {0};
    IVE_RECT_U16_S stRect = {0};
    stRect.u16X = (HI_U16)roi_left;
    stRect.u16Y = (HI_U16)roi_bottom;
    stRect.u16Width = (HI_U16)roi_width;
    stRect.u16Height = (HI_U16)roi_height;
    HI_S32 s32Ret = createRectImageByIVE(pstImage, &stRect, &stCroppedImage);
    SAMPLE_CHK_RET_VOID(s32Ret != HI_SUCCESS, "rectImageByIVE fail!");

    const HI_DOUBLE output_width = max(ceil(compute_output_w(pstTightBbox->x1, pstTightBbox->x2)), roi_width);
    const HI_DOUBLE output_height = max(ceil(compute_output_h(pstTightBbox->y1, pstTightBbox->y2)), roi_height);

    *pEdgeX = min(compute_edge_x(pstTightBbox->x1, pstTightBbox->x2), (HI_DOUBLE)(output_width - 1));
    *pEdgeY = min(compute_edge_y(pstTightBbox->y1, pstTightBbox->y2), (HI_DOUBLE)(output_height - 1));

    IVE_IMAGE_S stOutputImage = {0};
    s32Ret = createImageByIVE(&stOutputImage, pstImage->enType, (HI_U32)output_width, (HI_U32)output_height);
    if (s32Ret != HI_SUCCESS) {
        SAMPLE_LOG_INFO("createImageByIVE fail");
        freeIveImage(&stCroppedImage);
        return;
    }
    setIveImage(&stOutputImage, 0, 0, 0);

    IVE_RECT_U16_S stOutputRect;
    stOutputRect.u16X = (HI_U16)(*pEdgeX);
    stOutputRect.u16Y = (HI_U16)(*pEdgeY);
    stOutputRect.u16Width = (HI_U16)roi_width;
    stOutputRect.u16Height = (HI_U16)roi_height;
    s32Ret = copyImageByIVE(&stCroppedImage, &stOutputImage, &stOutputRect);
    if (s32Ret != HI_SUCCESS) {
        SAMPLE_LOG_INFO("copyImageByIVE fail!");
        freeIveImage(&stCroppedImage);
        freeIveImage(&stOutputImage);
        return;
    }

    memcpy((HI_CHAR *)pstTarget, (HI_CHAR *)&stOutputImage, sizeof(IVE_IMAGE_S));
    freeIveImage(&stCroppedImage);
    return;
}

typedef struct {
    IVE_IMAGE_S stImageC1;
    IVE_IMAGE_S stImageC2;
    IVE_IMAGE_S stImageC3;
    IVE_IMAGE_S stMeanC1;
    IVE_IMAGE_S stMeanC2;
    IVE_IMAGE_S stMeanC3;
    IVE_IMAGE_S stDstImageC1;
    IVE_IMAGE_S stDstImageC2;
    IVE_IMAGE_S stDstImageC3;
} ImageInfo;

typedef struct {
    HI_U8 B;
    HI_U8 G;
    HI_U8 R;
} BgrInfo;

static HI_S32 SetImageInfo(IVE_IMAGE_S *pstSrcImage, IVE_IMAGE_S *pstDstImage, ImageInfo *imageInfo)
{
    imageInfo->stImageC1.enType = IVE_IMAGE_TYPE_U8C1;
    imageInfo->stImageC2.enType = IVE_IMAGE_TYPE_U8C1;
    imageInfo->stImageC3.enType = IVE_IMAGE_TYPE_U8C1;
    imageInfo->stImageC1.u32Height = pstSrcImage->u32Height;
    imageInfo->stImageC2.u32Height = pstSrcImage->u32Height;
    imageInfo->stImageC3.u32Height = pstSrcImage->u32Height;
    imageInfo->stImageC1.u32Width = pstSrcImage->u32Width;
    imageInfo->stImageC2.u32Width = pstSrcImage->u32Width;
    imageInfo->stImageC3.u32Width = pstSrcImage->u32Width;
    imageInfo->stImageC1.au32Stride[0] = pstSrcImage->au32Stride[BLUE_IDX];
    imageInfo->stImageC2.au32Stride[0] = pstSrcImage->au32Stride[GREEN_IDX];
    imageInfo->stImageC3.au32Stride[0] = pstSrcImage->au32Stride[RED_IDX];
    imageInfo->stImageC1.au64PhyAddr[0] = pstSrcImage->au64PhyAddr[BLUE_IDX];
    imageInfo->stImageC2.au64PhyAddr[0] = pstSrcImage->au64PhyAddr[GREEN_IDX];
    imageInfo->stImageC3.au64PhyAddr[0] = pstSrcImage->au64PhyAddr[RED_IDX];
    imageInfo->stImageC1.au64VirAddr[0] = pstSrcImage->au64VirAddr[BLUE_IDX];
    imageInfo->stImageC2.au64VirAddr[0] = pstSrcImage->au64VirAddr[GREEN_IDX];
    imageInfo->stImageC3.au64VirAddr[0] = pstSrcImage->au64VirAddr[RED_IDX];

    imageInfo->stDstImageC1.enType = IVE_IMAGE_TYPE_U8C1;
    imageInfo->stDstImageC2.enType = IVE_IMAGE_TYPE_U8C1;
    imageInfo->stDstImageC3.enType = IVE_IMAGE_TYPE_U8C1;
    imageInfo->stDstImageC1.u32Height = pstDstImage->u32Height;
    imageInfo->stDstImageC2.u32Height = pstDstImage->u32Height;
    imageInfo->stDstImageC3.u32Height = pstDstImage->u32Height;
    imageInfo->stDstImageC1.u32Width = pstDstImage->u32Width;
    imageInfo->stDstImageC2.u32Width = pstDstImage->u32Width;
    imageInfo->stDstImageC3.u32Width = pstDstImage->u32Width;
    imageInfo->stDstImageC1.au32Stride[0] = pstDstImage->au32Stride[BLUE_IDX];
    imageInfo->stDstImageC2.au32Stride[0] = pstDstImage->au32Stride[GREEN_IDX];
    imageInfo->stDstImageC3.au32Stride[0] = pstDstImage->au32Stride[RED_IDX];
    imageInfo->stDstImageC1.au64PhyAddr[0] = pstDstImage->au64PhyAddr[BLUE_IDX];
    imageInfo->stDstImageC2.au64PhyAddr[0] = pstDstImage->au64PhyAddr[GREEN_IDX];
    imageInfo->stDstImageC3.au64PhyAddr[0] = pstDstImage->au64PhyAddr[RED_IDX];
    imageInfo->stDstImageC1.au64VirAddr[0] = pstDstImage->au64VirAddr[BLUE_IDX];
    imageInfo->stDstImageC2.au64VirAddr[0] = pstDstImage->au64VirAddr[GREEN_IDX];
    imageInfo->stDstImageC3.au64VirAddr[0] = pstDstImage->au64VirAddr[RED_IDX];

    return HI_SUCCESS;
}

static HI_S32 CreateImage(IVE_IMAGE_S *pstSrcImage, BgrInfo *bgrInfo, IVE_HANDLE *hIveHandle, ImageInfo *imageInfo)
{
    HI_U32 u32OneCBytes = pstSrcImage->au32Stride[0] * pstSrcImage->u32Height;
    IVE_SUB_CTRL_S stSubCtrl;
    stSubCtrl.enMode = IVE_SUB_MODE_ABS;

    HI_S32 s32Ret = createImageByIVE(&imageInfo->stMeanC1, IVE_IMAGE_TYPE_U8C1,
        pstSrcImage->u32Width, pstSrcImage->u32Height);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "createImageByIVE fail:%#x", s32Ret);
    memset ((HI_CHAR *)((uintptr_t)(imageInfo->stMeanC1.au64VirAddr[0])), bgrInfo->B, u32OneCBytes);

    s32Ret = createImageByIVE(&imageInfo->stMeanC2, IVE_IMAGE_TYPE_U8C1,
        pstSrcImage->u32Width, pstSrcImage->u32Height);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "createImageByIVE fail:%#x", s32Ret);
    memset ((HI_CHAR *)((uintptr_t)(imageInfo->stMeanC2.au64VirAddr[0])), bgrInfo->G, u32OneCBytes);

    s32Ret = createImageByIVE(&imageInfo->stMeanC3, IVE_IMAGE_TYPE_U8C1,
        pstSrcImage->u32Width, pstSrcImage->u32Height);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "createImageByIVE fail:%#x", s32Ret);
    memset ((HI_CHAR *)((uintptr_t)(imageInfo->stMeanC3.au64VirAddr[0])), bgrInfo->R, u32OneCBytes);

    s32Ret = HI_MPI_IVE_Sub(hIveHandle, &imageInfo->stImageC1, &imageInfo->stMeanC1,
        &imageInfo->stDstImageC1, &stSubCtrl, HI_FALSE);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "HI_MPI_IVE_Sub fail:%#x", s32Ret);

    s32Ret = HI_MPI_IVE_Sub(hIveHandle, &imageInfo->stImageC2, &imageInfo->stMeanC2,
        &imageInfo->stDstImageC2, &stSubCtrl, HI_FALSE);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "HI_MPI_IVE_Sub fail:%#x", s32Ret);

    s32Ret = HI_MPI_IVE_Sub(hIveHandle, &imageInfo->stImageC3, &imageInfo->stMeanC3,
        &imageInfo->stDstImageC3, &stSubCtrl, HI_TRUE);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "HI_MPI_IVE_Sub fail:%#x", s32Ret);

    return HI_SUCCESS;
FAIL_0:
    return HI_FAILURE;
}

static HI_S32 subImageByIVE(IVE_IMAGE_S *pstSrcImage, HI_U8 B, HI_U8 G, HI_U8 R, IVE_IMAGE_S *pstDstImage)
{
    SAMPLE_CHK_RET((pstSrcImage->enType != IVE_IMAGE_TYPE_U8C3_PLANAR), HI_FAILURE, "Not support image type[%u]",
                   pstSrcImage->enType);

    HI_BOOL bFinish = HI_FALSE;
    IVE_HANDLE hIveHandle = HI_NULL;

    struct timespec request_time;

    request_time.tv_sec = 0;
    request_time.tv_nsec = WAIT_TIME * MICROSECOND_PER_SECOND;
    BgrInfo bgrInfo = { B, G, R };

    ImageInfo imageInfo = {0};
    HI_S32 s32Ret = SetImageInfo(pstSrcImage, pstDstImage, &imageInfo);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "SetImageInfo fail:%#x", s32Ret);

    s32Ret = CreateImage(pstSrcImage, &bgrInfo, &hIveHandle, &imageInfo);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "CreateImage fail:%#x", s32Ret);

    s32Ret = HI_MPI_IVE_Query(hIveHandle, &bFinish, HI_TRUE);
    while (s32Ret == HI_ERR_IVE_QUERY_TIMEOUT) {
        nanosleep(&request_time, HI_NULL);
        SAMPLE_LOG_INFO("HI_MPI_IVE_Query timeout, wait 100us");
        s32Ret = HI_MPI_IVE_Query(hIveHandle, &bFinish, HI_TRUE);
    }
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "HI_MPI_IVE_Query fail:%#x", s32Ret);

FAIL_0:
    freeIveImage(&imageInfo.stMeanC1);
    freeIveImage(&imageInfo.stMeanC2);
    freeIveImage(&imageInfo.stMeanC3);

    return s32Ret;
}

HI_S32 resizeImageByIVE(IVE_IMAGE_S *pstSrcImage, IVE_IMAGE_S *pstDstImage)
{
    IVE_RESIZE_CTRL_S stResizeCtrl = {0};
    HI_RUNTIME_MEM_S stResizeMem = {0};
    IVE_HANDLE hIveHandle;
    HI_BOOL bFinish = HI_FALSE;
    struct timespec request_time;

    request_time.tv_sec = 0;
    request_time.tv_nsec = WAIT_TIME * MICROSECOND_PER_SECOND;

    if ((pstSrcImage->u32Height % 2 != 0) || (pstSrcImage->u32Width % 2 != 0)) {
        SAMPLE_LOG_INFO("Invalid input image size for input, must be a multiply of 2");
        return HI_FAILURE;
    }

    stResizeCtrl.enMode = IVE_RESIZE_MODE_LINEAR;
    stResizeCtrl.u16Num = 1;
    stResizeCtrl.stMem.u32Size = 49 * stResizeCtrl.u16Num;
    stResizeMem.u32Size = stResizeCtrl.stMem.u32Size;
    HI_S32 s32Ret = SAMPLE_AllocMem(&stResizeMem, HI_FALSE);
    stResizeCtrl.stMem.u64PhyAddr = stResizeMem.u64PhyAddr;
    stResizeCtrl.stMem.u64VirAddr = stResizeMem.u64VirAddr;
    SAMPLE_CHK_GOTO((s32Ret != HI_SUCCESS), FAIL_0, "SAMPLE_Utils_AllocMem fail:%#x", s32Ret);

    s32Ret = HI_MPI_IVE_Resize(&hIveHandle, pstSrcImage, pstDstImage, &stResizeCtrl, HI_TRUE);
    SAMPLE_CHK_GOTO((s32Ret != HI_SUCCESS), FAIL_0, "HI_MPI_IVE_Resize fail:%#x", s32Ret);

    s32Ret = HI_MPI_IVE_Query(hIveHandle, &bFinish, HI_TRUE);
    while (s32Ret == HI_ERR_IVE_QUERY_TIMEOUT) {
        nanosleep(&request_time, HI_NULL);
        SAMPLE_LOG_INFO("HI_MPI_IVE_Query timeout, wait 100us");
        s32Ret = HI_MPI_IVE_Query(hIveHandle, &bFinish, HI_TRUE);
    }
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "Error(%#x), HI_MPI_IVE_Query failed!", s32Ret);
FAIL_0:
    SAMPLE_FreeMem(&stResizeMem);

    return s32Ret;
}

// 227*227--->228*228---->227*227
static HI_S32 ProcessingEvenImage(IVE_IMAGE_S *pstSrcImage, IVE_IMAGE_S *pstDstImage)
{
    IVE_IMAGE_S stTempMean = {0};
    HI_U32 u32Width = pstSrcImage->u32Width;
    HI_U32 u32Height = pstSrcImage->u32Height;
    IVE_RECT_U16_S stDstRect = {0};
    IVE_IMAGE_S stTempDst = {0};

    HI_S32 s32Ret = createImageByIVE(&stTempMean, pstSrcImage->enType, u32Width + u32Width % 2,
        u32Height + u32Height % 2);
    SAMPLE_CHK_GOTO((s32Ret != HI_SUCCESS), FAIL_0, "createImageByIVE 1 fail:%#x", s32Ret);

    stDstRect.u16X = 0;
    stDstRect.u16Y = 0;
    stDstRect.u16Width = u32Width;
    stDstRect.u16Height = u32Height;
    s32Ret = copyImageByIVE(pstSrcImage, &stTempMean, &stDstRect);
    SAMPLE_CHK_GOTO((s32Ret != HI_SUCCESS), FAIL_0, "copyImageByIVE 1 fail:%#x", s32Ret);

    if ((stTempMean.u32Height != pstDstImage->u32Height) || (stTempMean.u32Width != pstDstImage->u32Width)) {
        s32Ret = createImageByIVE(&stTempDst, pstSrcImage->enType,
                                  u32Width + u32Width % 2, u32Height + u32Height % 2);
        SAMPLE_CHK_GOTO((s32Ret != HI_SUCCESS), FAIL_0, "createImageByIVE 2 fail:%#x", s32Ret);

        s32Ret = subImageByIVE(&stTempMean, IMG_MEAN_B_VAL, IMG_MEAN_G_VAL, IMG_MEAN_R_VAL, &stTempDst);
        SAMPLE_CHK_GOTO((s32Ret != HI_SUCCESS), FAIL_0, "subImageByIVE 1 fail:%#x", s32Ret);

        stDstRect.u16X = 0;
        stDstRect.u16Y = 0;
        stDstRect.u16Width = pstDstImage->u32Width;
        stDstRect.u16Height = pstDstImage->u32Height;
        s32Ret = copyImageByIVE(&stTempMean, pstDstImage, &stDstRect);
        SAMPLE_CHK_GOTO((s32Ret != HI_SUCCESS), FAIL_0, "copyImageByIVE 2 fail:%#x", s32Ret);

    } else {
        s32Ret = subImageByIVE(&stTempMean, IMG_MEAN_B_VAL, IMG_MEAN_G_VAL, IMG_MEAN_R_VAL, pstDstImage);
        SAMPLE_CHK_GOTO((s32Ret != HI_SUCCESS), FAIL_0, "subImageByIVE 2 fail:%#x", s32Ret);
    }

FAIL_0:
    freeIveImage(&stTempMean);
    freeIveImage(&stTempDst);
    return s32Ret;
}

// 228*228--->228*228---->227*227
static HI_S32 ProcessingOddImage(IVE_IMAGE_S *pstSrcImage, IVE_IMAGE_S *pstDstImage)
{
    IVE_RECT_U16_S stDstRect = {0};
    IVE_IMAGE_S stTempDst = {0};
    HI_S32 s32Ret = HI_FAILURE;

    if ((pstDstImage->u32Height != pstSrcImage->u32Height) || (pstDstImage->u32Width != pstSrcImage->u32Width)) {
        s32Ret = createImageByIVE(&stTempDst, pstSrcImage->enType, pstSrcImage->u32Width, pstSrcImage->u32Height);
        SAMPLE_CHK_GOTO((s32Ret != HI_SUCCESS), FAIL_0, "createImageByIVE 3 fail:%#x", s32Ret);

        s32Ret = subImageByIVE(pstSrcImage, IMG_MEAN_B_VAL, IMG_MEAN_G_VAL, IMG_MEAN_R_VAL, &stTempDst);
        SAMPLE_CHK_GOTO((s32Ret != HI_SUCCESS), FAIL_0, "subImageByIVE 3 fail:%#x", s32Ret);

        stDstRect.u16X = 0;
        stDstRect.u16Y = 0;
        stDstRect.u16Width = pstDstImage->u32Width;
        stDstRect.u16Height = pstDstImage->u32Height;
        s32Ret = copyImageByIVE(&stTempDst, pstDstImage, &stDstRect);
        SAMPLE_CHK_GOTO((s32Ret != HI_SUCCESS), FAIL_0, "copyImageByIVE 3 fail:%#x", s32Ret);
    } else {
        s32Ret = subImageByIVE(pstSrcImage, IMG_MEAN_B_VAL, IMG_MEAN_G_VAL, IMG_MEAN_R_VAL, pstDstImage);
        SAMPLE_CHK_GOTO((HI_SUCCESS), FAIL_0, "subImageByIVE 4 fail:%#x", s32Ret);
    }
FAIL_0:
    freeIveImage(&stTempDst);
    return s32Ret;
}

static HI_S32 meanImageByIVE(IVE_IMAGE_S *pstSrcImage, IVE_IMAGE_S *pstDstImage)
{
    HI_S32 s32Ret = HI_FAILURE;

    if ((pstSrcImage->u32Height % 2 != 0) || (pstSrcImage->u32Width % 2 != 0)) {
        s32Ret = ProcessingEvenImage(pstSrcImage, pstDstImage);
        SAMPLE_CHK_RET((s32Ret != HI_SUCCESS), HI_FAILURE, "ProcessingEvenImage fail");
    } else {
        s32Ret = ProcessingOddImage(pstSrcImage, pstDstImage);
        SAMPLE_CHK_RET((s32Ret != HI_SUCCESS), HI_FAILURE, "ProcessingEvenImage fail");
    }

    return s32Ret;
}

static HI_S32 goTurnImagePreprocessByIVE(IVE_IMAGE_S *pstSrcImage, IVE_IMAGE_S *pstDstImage)
{
    HI_S32 s32Ret = HI_FAILURE;
    HI_U32 u32Height = pstDstImage->u32Height;
    HI_U32 u32Width = pstDstImage->u32Width;
    IVE_IMAGE_S stResizeImage = {0};

    if ((pstSrcImage->u32Height != u32Height) || (pstSrcImage->u32Width != u32Width)) {
        s32Ret = createImageByIVE(&stResizeImage, pstSrcImage->enType,
                                  u32Width + u32Width % 2, u32Height + u32Height % 2);
        SAMPLE_CHK_GOTO((s32Ret != HI_SUCCESS), FAIL_0, "createImageByIVE fail:%#x", s32Ret);

        s32Ret = resizeImageByIVE(pstSrcImage, &stResizeImage);
        SAMPLE_CHK_GOTO((s32Ret != HI_SUCCESS), FAIL_0, "resizeImageByIVE fail:%#x", s32Ret);

        s32Ret = meanImageByIVE(&stResizeImage, pstDstImage);
        SAMPLE_CHK_GOTO((s32Ret != HI_SUCCESS), FAIL_0, "meanImageByIVE fail:%#x", s32Ret);

    } else {
        s32Ret = meanImageByIVE(pstSrcImage, pstDstImage);
        SAMPLE_CHK_GOTO((s32Ret != HI_SUCCESS), FAIL_0, "meanImageByIVE fail:%#x", s32Ret);
    }

FAIL_0:
    freeIveImage(&stResizeImage);
    return s32Ret;
}

static HI_S32 goTurnReadInputDataByIVE(IVE_IMAGE_S *pstSrcImage, HI_RUNTIME_BLOB_S *pstBlobs, HI_U16 index)
{
    IVE_IMAGE_S stDstImage = {0};

    HI_S32 s32Ret = createImageByIVE(&stDstImage, pstSrcImage->enType, pstBlobs->unShape.stWhc.u32Width,
                                     pstBlobs->unShape.stWhc.u32Height);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "createImageByIVE fail:%#x", s32Ret);
    setIveImage(&stDstImage, 100, 100, 100); // BGR(100,100,100) gray

    s32Ret = goTurnImagePreprocessByIVE(pstSrcImage, &stDstImage);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "goTurnImagePreprocessByIVE fail:%#x", s32Ret);

    s32Ret = copyIveImage2Blob(&stDstImage, pstBlobs, index);
FAIL_0:
    freeIveImage(&stDstImage);
    return s32Ret;
}

HI_S32 cropPadBlobByIVE(const HI_RUNTIME_BLOB_S *pstSrcBlob, const HI_RUNTIME_BLOB_S *pstBboxBlob,
    HI_RUNTIME_BLOB_S *pstDstBlob, TRACKER_LOCATION_S *pstLocation, HI_S32 *ps32EdgeX, HI_S32 *ps32EdgeY,
    HI_S32 *ps32RegionW, HI_S32 *ps32RegionH)
{
    IVE_IMAGE_S stImage = {0};
    IVE_IMAGE_S stTarget = {0};

    if (pstBboxBlob->unShape.stWhc.u32Width != 4) {
        SAMPLE_LOG_INFO("Error bbox blob u32Num[%u]", pstBboxBlob->u32Num);
        return HI_FAILURE;
    }

    HI_S32 s32Ret = createImageByIVE(&stImage, IVE_IMAGE_TYPE_U8C3_PLANAR, pstSrcBlob->unShape.stWhc.u32Width,
                                     pstSrcBlob->unShape.stWhc.u32Height);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "createImageByIVE fail");

    s32Ret = copyBlob2IveImage(pstSrcBlob, 0, &stImage);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "copyBlob2IveImage fail");

    BondingBox_s stTightBbox;
    BondingBox_s stBboxLocation;
    HI_DOUBLE dEdgeX = 0;
    HI_DOUBLE dEdgeY = 0;

    HI_U32 u32OffSet = pstBboxBlob->unShape.stWhc.u32Chn * pstBboxBlob->unShape.stWhc.u32Height *
                       pstBboxBlob->u32Stride;
    for (HI_U32 i = 0; i < pstBboxBlob->u32Num; i++) {
        HI_S32 *ps32Dst = (HI_S32 *)((HI_U8 *)((uintptr_t)(pstBboxBlob->u64VirAddr)) + i * u32OffSet);
        stTightBbox.x1 = (HI_DOUBLE) * (ps32Dst + X_MIN_IDX);
        stTightBbox.y1 = (HI_DOUBLE) * (ps32Dst + Y_MIN_IDX);
        stTightBbox.x2 = (HI_DOUBLE) * (ps32Dst + X_MAX_IDX);
        stTightBbox.y2 = (HI_DOUBLE) * (ps32Dst + Y_MAX_IDX);

        cropImageByIVE(&stImage, &stTightBbox, &stTarget, &stBboxLocation, &dEdgeX, &dEdgeY);
        SAMPLE_CHK_GOTO(0 == stTarget.u32Height, FAIL_0, "cropImageByIVE fail!");

        goTurnReadInputDataByIVE(&stTarget, pstDstBlob, i);

        pstLocation[i].x1 = (HI_S32)(stBboxLocation.x1 * SVP_WK_QUANT_BASE);
        pstLocation[i].y1 = (HI_S32)(stBboxLocation.y1 * SVP_WK_QUANT_BASE);
        pstLocation[i].x2 = (HI_S32)(stBboxLocation.x2 * SVP_WK_QUANT_BASE);
        pstLocation[i].y2 = (HI_S32)(stBboxLocation.y2 * SVP_WK_QUANT_BASE);
        ps32EdgeX[i] = (HI_S32)(dEdgeX * SVP_WK_QUANT_BASE);
        ps32EdgeY[i] = (HI_S32)(dEdgeY * SVP_WK_QUANT_BASE);
        ps32RegionW[i] = stTarget.u32Width;
        ps32RegionH[i] = stTarget.u32Height;

        SAMPLE_LOG_INFO("location %d: (%f,%f)(%f,%f)", i, stBboxLocation.x1, stBboxLocation.y1, stBboxLocation.x2,
            stBboxLocation.y2);
        SAMPLE_LOG_INFO("edge %d: %f,%f ; %d,%d ", i, dEdgeX, dEdgeY, stTarget.u32Width, stTarget.u32Height);
        freeIveImage(&stTarget);
    }

FAIL_0:
    freeIveImage(&stImage);

    return HI_SUCCESS;
}

HI_S32 resizeByIVE(const HI_RUNTIME_BLOB_S *pstSrcBlob, HI_RUNTIME_BLOB_S *pstDstBlob)
{
    IVE_IMAGE_S stSrcImage = {0};
    IVE_IMAGE_S stDstImage = {0};
    IVE_IMAGE_S stDstTemp = {0};
    IVE_RECT_U16_S stDstRect = {0};
    HI_U32 u32Width = pstDstBlob->unShape.stWhc.u32Width + pstDstBlob->unShape.stWhc.u32Width % 2;
    HI_U32 u32Height = pstDstBlob->unShape.stWhc.u32Height + pstDstBlob->unShape.stWhc.u32Height % 2;

    HI_S32 s32Ret = createImageByIVE(&stSrcImage, IVE_IMAGE_TYPE_U8C3_PLANAR, pstSrcBlob->unShape.stWhc.u32Width,
                                     pstSrcBlob->unShape.stWhc.u32Height);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "createImageByIVE fail!");

    s32Ret = createImageByIVE(&stDstImage, IVE_IMAGE_TYPE_U8C3_PLANAR, u32Width, u32Height);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "createImageByIVE fail!");

    s32Ret = copyBlob2IveImage(pstSrcBlob, 0, &stSrcImage);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "copyBlob2IveImage fail!");

    s32Ret = resizeImageByIVE(&stSrcImage, &stDstImage);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "resizeImageByIVE fail!");

    if ((stDstImage.u32Height != pstDstBlob->unShape.stWhc.u32Height) ||
        (stDstImage.u32Width != pstDstBlob->unShape.stWhc.u32Width)) {
        s32Ret = createImageByIVE(&stDstTemp, IVE_IMAGE_TYPE_U8C3_PLANAR, pstDstBlob->unShape.stWhc.u32Width,
                                  pstDstBlob->unShape.stWhc.u32Height);
        SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "createImageByIVE fail!");

        stDstRect.u16X = 0;
        stDstRect.u16Y = 0;
        stDstRect.u16Width = pstDstBlob->unShape.stWhc.u32Width;
        stDstRect.u16Height = pstDstBlob->unShape.stWhc.u32Height;
        s32Ret = copyImageByIVE(&stDstImage, &stDstTemp, &stDstRect);
        SAMPLE_CHK_GOTO((s32Ret != HI_SUCCESS), FAIL_0, "copyImageByIVE fail:%#x", s32Ret);

        s32Ret = copyIveImage2Blob(&stDstTemp, pstDstBlob, 0);
        SAMPLE_CHK_GOTO((s32Ret != HI_SUCCESS), FAIL_0, "copyIveImage2Blob fail:%#x", s32Ret);
    } else {
        s32Ret = copyIveImage2Blob(&stDstImage, pstDstBlob, 0);
        SAMPLE_CHK_GOTO((s32Ret != HI_SUCCESS), FAIL_0, "copyIveImage2Blob fail:%#x", s32Ret);
    }
FAIL_0:
    freeIveImage(&stSrcImage);
    freeIveImage(&stDstImage);
    freeIveImage(&stDstTemp);
    return s32Ret;
}

HI_VOID savePPMImage(const HI_CHAR *pszPicPath, IVE_IMAGE_S *pstImage)
{
    HI_CHAR aszAbsDirPath[PATH_MAX + 1];
    HI_CHAR aszAbsFilePath[PATH_MAX + 1];
    HI_CHAR aszPicPathForDirName[PATH_MAX + 1];
    HI_CHAR aszPicPathForBaseName[PATH_MAX + 1];
    HI_CHAR *pszDirName = HI_NULL;
    HI_CHAR *pszBaseName = HI_NULL;

    SAMPLE_CHK_RET_VOID(((pszPicPath == HI_NULL) ||
                         (strlen(pszPicPath) > PATH_MAX)),
                        "invalid pic path(%s) is NULL or too long", pszPicPath);

    memset(aszPicPathForDirName, 0, sizeof(aszPicPathForDirName));
    memset(aszPicPathForBaseName, 0, sizeof(aszPicPathForBaseName));

    strncpy(aszPicPathForDirName, pszPicPath, PATH_MAX);
    strncpy(aszPicPathForBaseName, pszPicPath, PATH_MAX);

    pszDirName = dirname(aszPicPathForDirName);
    SAMPLE_CHK_RET_VOID(((pszDirName == HI_NULL) || (strlen(pszDirName) == 0)), "dirname(%s) error", pszPicPath);
    pszBaseName = basename(aszPicPathForBaseName);
    SAMPLE_CHK_RET_VOID(((pszBaseName == HI_NULL) || (strlen(pszBaseName) == 0)), "basename(%s) error", pszPicPath);

    SAMPLE_CHK_RET_VOID((pszBaseName[strlen(pszBaseName) - 1] == '.' || pszBaseName[strlen(pszBaseName) - 1] == '/'),
                        "invalid path[%s]: miss file name", pszPicPath);

    memset(aszAbsDirPath, 0, sizeof(aszAbsDirPath));
    SAMPLE_CHK_RET_VOID(HI_NULL == realpath(pszDirName, aszAbsDirPath), "realpath fail");

    SAMPLE_CHK_RET_VOID((strlen(aszAbsDirPath) + strlen(pszBaseName) + 1 > PATH_MAX), "aszAbsDirPath[%s%s] too long",
                        aszAbsDirPath, pszBaseName);

    HI_S32 s32Ret = snprintf(aszAbsFilePath, sizeof(aszAbsFilePath), "%s/%s", aszAbsDirPath, pszBaseName);
    SAMPLE_CHK_RET_VOID(s32Ret <= 0, "snprintf absFileName fail");

    FILE *ppmFile = fopen(aszAbsFilePath, "wb");
    SAMPLE_CHK_RET_VOID(HI_NULL == ppmFile, "open file %s fail!", aszAbsFilePath);
    fprintf(ppmFile, "P6\n%d %d\n255\n", pstImage->u32Width, pstImage->u32Height);

    unsigned char *pucImageC0 = (unsigned char *)((uintptr_t)pstImage->au64VirAddr[BLUE_IDX]);
    unsigned char *pucImageC1 = (unsigned char *)((uintptr_t)pstImage->au64VirAddr[GREEN_IDX]);
    unsigned char *pucImageC2 = (unsigned char *)((uintptr_t)pstImage->au64VirAddr[RED_IDX]);

    unsigned char aucPixel[3]; // 3 channel
    for (HI_U32 i = 0; i < pstImage->u32Height; i++) {
        for (HI_U32 j = 0; j < pstImage->u32Width; j++) {
            aucPixel[RED_IDX] = pucImageC0[i * pstImage->au32Stride[BLUE_IDX] + j];
            aucPixel[GREEN_IDX] = pucImageC1[i * pstImage->au32Stride[GREEN_IDX] + j];
            aucPixel[BLUE_IDX] = pucImageC2[i * pstImage->au32Stride[RED_IDX] + j];

            s32Ret = fwrite(aucPixel, 3, 1, ppmFile); // 3 channel
            if (s32Ret != 1) {
                fclose(ppmFile);
                return;
            }
        }
    }
    fclose(ppmFile);
    return;
}

HI_VOID drawImageRectByIVE(const HI_CHAR aszFileName[PATH_MAX], const HI_RUNTIME_BLOB_S *pstBlob,
                           HI_S32 as32Coord[], HI_U32 u32CoordCnt, HI_U32 u32CoordStride)
{
    IVE_IMAGE_S stSrcImage = {0};
    IVE_IMAGE_S stRectImage = {0};
    IVE_IMAGE_S stBluePatch = {0};
    IVE_RECT_U16_S stRect = {0};

    HI_S32 s32Ret = createImageByIVE(&stSrcImage, IVE_IMAGE_TYPE_U8C3_PLANAR, pstBlob->unShape.stWhc.u32Width,
        pstBlob->unShape.stWhc.u32Height);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "createImageByIVE fail!");

    s32Ret = copyBlob2IveImage(pstBlob, 0, &stSrcImage);
    SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "copyBlob2IveImage fail!");

    for (HI_U32 i = 0; i < u32CoordCnt; i++) {
        stRect.u16X = as32Coord[i * u32CoordStride] + 1;
        stRect.u16Y = as32Coord[i * u32CoordStride + 1] + 1;
        stRect.u16Width = as32Coord[i * u32CoordStride + X_MAX_IDX] - as32Coord[i * u32CoordStride + X_MIN_IDX] - 2;
        stRect.u16Height = as32Coord[i * u32CoordStride + Y_MAX_IDX] - as32Coord[i * u32CoordStride + Y_MIN_IDX] - 2;
        s32Ret = createRectImageByIVE(&stSrcImage, &stRect, &stRectImage);
        SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "createRectImageByIVE fail!");

        s32Ret = createImageByIVE(&stBluePatch, IVE_IMAGE_TYPE_U8C3_PLANAR,
            as32Coord[i * u32CoordStride + X_MAX_IDX] - as32Coord[i * u32CoordStride + X_MIN_IDX],
            as32Coord[i * u32CoordStride + Y_MAX_IDX] - as32Coord[i * u32CoordStride + Y_MIN_IDX]);
        SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "createImageByIVE fail!");

        setIveImage(&stBluePatch, 0, 0, 255); // red line

        stRect.u16X = as32Coord[i * u32CoordStride + X_MIN_IDX];
        stRect.u16Y = as32Coord[i * u32CoordStride + Y_MIN_IDX];
        stRect.u16Width = as32Coord[i * u32CoordStride + X_MAX_IDX] - as32Coord[i * u32CoordStride + X_MIN_IDX];
        stRect.u16Height = as32Coord[i * u32CoordStride + Y_MAX_IDX] - as32Coord[i * u32CoordStride + Y_MIN_IDX];
        s32Ret = copyImageByIVE(&stBluePatch, &stSrcImage, &stRect);
        freeIveImage(&stBluePatch);
        SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "copyImageByIVE fail!");

        stRect.u16X = as32Coord[i * u32CoordStride + X_MIN_IDX] + 1;
        stRect.u16Y = as32Coord[i * u32CoordStride + Y_MIN_IDX] + 1;
        stRect.u16Width = as32Coord[i * u32CoordStride + X_MAX_IDX] - as32Coord[i * u32CoordStride + X_MIN_IDX] - 2;
        stRect.u16Height = as32Coord[i * u32CoordStride + Y_MAX_IDX] - as32Coord[i * u32CoordStride + Y_MIN_IDX] - 2;
        s32Ret = copyImageByIVE(&stRectImage, &stSrcImage, &stRect);
        freeIveImage(&stRectImage);
        SAMPLE_CHK_GOTO(s32Ret != HI_SUCCESS, FAIL_0, "copyImageByIVE fail!");
    }
    SAMPLE_LOG_INFO("save %s", aszFileName);
    savePPMImage(aszFileName, &stSrcImage);
FAIL_0:
    freeIveImage(&stSrcImage);
    freeIveImage(&stBluePatch);
    freeIveImage(&stRectImage);
    return;
}

HI_VOID saveBlobByIVE(const HI_CHAR aszPath[PATH_MAX], const HI_RUNTIME_BLOB_S *pstSrcBlob, HI_U16 u16Index)
{
    IVE_IMAGE_S stImage = {0};

    HI_S32 s32Ret = copyBlob2IveImage(pstSrcBlob, u16Index, &stImage);
    if (s32Ret == HI_SUCCESS) {
        savePPMImage(aszPath, &stImage);
    }
    freeIveImage(&stImage);
}
#endif
